
// Copyright (C) 2009-2011 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace Derm.Scene.Mesh
{
	/// <summary>
	/// Mesh encoder/decoder abstraction. 
	/// </summary>
	public sealed class MeshCodec : PluginLoader<IMeshCodecPlugin>
	{
		#region Constructors

		/// <summary>
		/// This type is a singleton.
		/// </summary>
		private MeshCodec()
		{
			// Register plugin placed in the current directory
			LoadImageCodecPlugins(Directory.GetCurrentDirectory(), PluginFactoryType);
			// Register plugin placed in %DERM_IMAGE_CODEC_DIR%
			string dermImageCodecDir = Environment.GetEnvironmentVariable("DERM_MESH_CODEC_DIR");
			if ((dermImageCodecDir != null) && (Directory.Exists(dermImageCodecDir) == true))
				LoadImageCodecPlugins(dermImageCodecDir, PluginFactoryType);
		}

		/// <summary>
		/// The type which following plugin factory conventions.
		/// </summary>
		private const string PluginFactoryType = "Derm.MeshCodecFactory";
		
		#endregion

		#region Singleton

		/// <summary>
		/// The only instance of MeshCodec.
		/// </summary>
		public static readonly MeshCodec Instance = new MeshCodec();

		#endregion
		
		#region Mesh Loading
		
		/// <summary>
		/// Load a Mesh from a file.
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/> that specifies the path of the file.
		/// </param>
		/// <returns>
		/// It returns a <see cref="Mesh"/> loaded from the file located at <paramref name="path"/>
		/// </returns>
		public Mesh Load(string path)
		{
			Mesh mesh = null;

			if (path == null)
				throw new ArgumentNullException("path");
			
			Console.WriteLine("Opening mesh at {0}.", path);
			
			// Get supported plugins
			IEnumerable<IMeshCodecPlugin> plugins = GetSupportedPlugins(path);

			foreach (IMeshCodecPlugin p in plugins) {
				using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
					// Load image pixel data
					mesh = p.Load(fs);

					if (mesh != null)
						break;
				}
				break;
			}
			
			if (mesh == null)
				throw new Exception("Not codec was able to open "+path+".");
			
			return (mesh);
		}
		
		#endregion
		
		#region Mesh Codec Plugin Management
		
		/// <summary>
		/// Get supported plugin for the specified path. 
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="List{Plugin}"/>
		/// </returns>
		private IEnumerable<IMeshCodecPlugin> GetSupportedPlugins(string path)
		{
			List<IMeshCodecPlugin> plugins = new List<IMeshCodecPlugin>();

			// Get plugins handling this file (probe by extension)
			foreach (IMeshCodecPlugin p in Plugins) {
				// Check support for each plugin
				if (p.IsSupported(path) == true)
					plugins.Add(p);
			}

			return (plugins);
		}

		#endregion
	}
}
